package com.thoughtworks.impersonator.http.message;

import java.io.Reader;
import java.io.StringReader;
import java.util.Map;
import java.util.TreeMap;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
import org.jboss.netty.handler.codec.http.HttpResponse;
import org.jboss.netty.handler.codec.http.HttpResponseStatus;
import org.jboss.netty.handler.codec.http.HttpVersion;

public class RawResponse extends Message {
    private Integer statusCode;
    private String reasonPhrase;
    private String protocol;

    public RawResponse(HttpResponse response) {
        StringBuilder responseText = new StringBuilder();
        HttpResponseStatus responseStatus = response.getStatus();
        responseText.append(
                String.format("%s %d %s", "HTTP/1.1", responseStatus.getCode(), responseStatus.getReasonPhrase()))
                .append("\r\n");
        for (String headerName : response.getHeaderNames()) {
            String headerValue = response.getHeader(headerName);
            responseText.append(headerName).append(": ").append(headerValue).append("\r\n");
        }
        // TODO: should we use the correct content-type?
        responseText.append("\r\n").append(response.getContent().toString("utf-8"));
        load(new StringReader(responseText.toString()));
    }

    public RawResponse(String contents) {
        this(new StringReader(contents));
    }

    public RawResponse(Reader reader) {
        load(reader);
    }

    @Override
    protected void setStartLineElements(String firstElement, String secondElement, String thirdElement) {
        protocol = firstElement;
        statusCode = Integer.parseInt(secondElement);
        reasonPhrase = thirdElement;
    }

    @Override
    public void setBody(String body) {
        super.setBody(body);
        setHeader("Content-Length", Integer.toString(body.length()));
    }

    @Override
    protected String getStartLine() {
        return String.format("%s %d %s", protocol, statusCode, reasonPhrase);
    }

    public Integer getStatusCode() {
        return statusCode;
    }

    public String getReasonPhrase() {
        return reasonPhrase;
    }

    public String getProtocol() {
        return protocol;
    }

    private String getEncoding() {
        String contentType = getHeader("Content-Type");
        String charset = "charset=";
        if (contentType != null && contentType.contains(charset)) {
            return contentType.substring(contentType.indexOf(charset) + charset.length());
        } else {
            return "ISO-8859-1";
        }
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (obj == this) {
            return true;
        }
        if (obj.getClass() != getClass()) {
            return false;
        }
        RawResponse rhs = (RawResponse) obj;
        String lbody = super.getBody().trim().replace("\n", "").replace("\r", "");
        String rbody = rhs.getBody().trim().replace("\n", "").replace("\r", "");

        Map<String, String> lheaders = new TreeMap<String, String>(super.getHeaders());
        removeHeaders(lheaders);
        normalizeContentLength(lheaders, lbody);
        Map<String, String> rheaders = new TreeMap<String, String>(rhs.getHeaders());
        removeHeaders(rheaders);
        normalizeContentLength(rheaders, rbody);

        return new EqualsBuilder().append(statusCode, rhs.statusCode).append(reasonPhrase, rhs.reasonPhrase).append(
                protocol, rhs.protocol).append(lbody, rbody).append(lheaders, rheaders).isEquals();
    }

    private void removeHeaders(Map<String, String> headersMap) {
        headersMap.remove("Date");
        headersMap.remove("Server");
        headersMap.remove("Expires");
        headersMap.remove("Set-Cookie");
        headersMap.remove("Last-Modified");
        headersMap.remove("Cache-Control");
        headersMap.remove("Pragma");
        headersMap.remove("Via");
    }

    private void normalizeContentLength(Map<String, String> headersMap, String body) {
        headersMap.put("Content-Length", "" + body.length());
    }

    public HttpResponse toHttpResponse() {
        HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
        for (String headerName : getHeaderNames()) {
            response.setHeader(headerName, getHeader(headerName));
        }
        ChannelBuffer content = ChannelBuffers.copiedBuffer(getBody(), getEncoding());
        response.setContent(content);
        return response;
    }

}
